package at.fhooe.mcm.logic.core;

import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import at.fhooe.mcm.logic.dataexport.DataExportService;
import at.fhooe.mcm.logic.event.EventManager;
import at.fhooe.mcm.logic.logging.ConsoleLoggingService;
import at.fhooe.mcm.logic.network.NetworkService;
import at.fhooe.mcm.logic.sensors.SensorFactory;
import at.fhooe.mcm.logic.sensors.SensorManager;

public class Core implements Runnable
{
	private static final String		LOGGING_SOURCE			= "Core";
	private static boolean			m_isUpdatingServices	= false;
	private static Core				m_core;
	
	private Map<String, Service>	m_services				= new HashMap<String, Service>();
	private List<UpdateableService>	m_updateables			= new ArrayList<UpdateableService>();
	private Thread m_thread;
	private static ConsoleLoggingService m_consoleLogService = null;

	public static Core createServerCore(int _loggingLevel, int _port) throws IOException
	{
		m_core = new Core();
		m_consoleLogService = new ConsoleLoggingService(_loggingLevel);
		m_core.installService(m_consoleLogService);
		m_core.installService(new NameService());
		m_core.installService(new EventManager());
		m_core.installService(new SensorManager());
		m_core.installService(new SensorFactory());
		m_core.installService(new DataExportService());
		m_core.installService(new NetworkService(_port));
		
		Runtime.getRuntime().addShutdownHook(new Thread(){
			public void run() {
				m_core.shutdown();
			}
		});

		m_isUpdatingServices = true;
		return m_core;
	}

	@Deprecated
	public static Core createTestCore(int loggingLevel)
	{
		m_core = new Core();
		m_core.installService(new ConsoleLoggingService(loggingLevel));
		m_core.installService(new NameService());
		m_core.installService(new EventManager());
		m_core.installService(new SensorManager());
		m_core.installService(new SensorFactory());
		m_core.installService(new DataExportService());
	

		m_isUpdatingServices = true;
		return m_core;
	}
	
	public void start()
	{
		m_thread = new Thread(this);
		m_thread.start();
	}
	
	public void shutdown() 
	{
		m_core.uninstallService(NameService.getInstance(m_core));
		m_core.uninstallService(EventManager.getInstance(m_core));
		m_core.uninstallService(SensorManager.getInstance(m_core));
		m_core.uninstallService(SensorFactory.getInstance(m_core));
		m_core.uninstallService(DataExportService.getInstance(m_core));
		m_core.uninstallService(NetworkService.getInstance(m_core));
		m_core.uninstallService(ConsoleLoggingService.getInstance(m_core));
	}
	
	public void uninstallService(Service service)
	{
		if(hasService(service.getName()))
		{
			service.shutdown(this);
			m_services.remove(service);
		}
		
		if (hasService(ConsoleLoggingService.NAME))
		{
			String msg;

			if (service instanceof UpdateableService)
			{
				msg = "updateable service '" + service.getName() + "' installed";
			}
			else
			{
				msg = "service '" + service.getName() + "' installed";
			}

			ConsoleLoggingService.getInstance(this).logDebug(LOGGING_SOURCE, msg);
		}
	}

	public void installService(Service service)
	{
		if (hasService(service.getName()))
		{
			throw new RuntimeException("service '" + service.getName() + "' already installed");
		}

		m_services.put(service.getName(), service);

		if (service instanceof UpdateableService)
		{
			m_updateables.add((UpdateableService) service);
		}

		service.initialize(this);

		if (hasService(ConsoleLoggingService.NAME))
		{
			String msg;

			if (service instanceof UpdateableService)
			{
				msg = "updateable service '" + service.getName() + "' installed";
			}
			else
			{
				msg = "service '" + service.getName() + "' installed";
			}

			ConsoleLoggingService.getInstance(this).logDebug(LOGGING_SOURCE, msg);
		}
	}

	public boolean hasService(String name)
	{
		return m_services.containsKey(name);
	}

	public Service getService(String name)
	{
		Service service = m_services.get(name);
		if (service == null)
		{
			throw new RuntimeException("service '" + name + "' not found");
		}

		return service;
	}

	public Date getTime()
	{
		return new Date();
	}

	@Override
	public void run()
	{
		while (m_isUpdatingServices)
		{
			try
			{
				for (Iterator<UpdateableService> it = m_updateables.iterator(); it.hasNext();)
				{
					it.next().update();
				}
				Thread.sleep(10);
			}
			catch (InterruptedException e)
			{
				ConsoleLoggingService.getInstance(this).logInfo(LOGGING_SOURCE, e.getMessage());
			}
		}
	}
	
	public void redirectConsoleLoggingOutput(OutputStream _os)
	{
		m_consoleLogService.redirectLogOutput(_os);
	}

	@Deprecated
	public void update()
	{
		for (Iterator<UpdateableService> it = m_updateables.iterator(); it.hasNext();)
		{
			it.next().update();
		}
	}

}
